#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <signal.h>
#include <fcntl.h>
using namespace std;

const int BUF_SIZE = 1024;

static int connfd;

void sig_urg (int sig) {
    int save_errno = errno;
    char buffer[BUF_SIZE];
    memset (buffer, 0, BUF_SIZE);
    int ret = recv (connFd, buffer, BUF_SIZE - 1, MSG_OOB);
    cout << "got " << ret << " bytes of oob data " << buffer << endl;
    errno = save_errno;
}

void addsig (int sig, void (*sig_handler)(int)) {
    struct sigaction sa;
    memset (&sa, 0, sizeof(sa));
    sa.sa_handler = sig_handler;
    sa.sa_flags |= SA_RESTART;
    sigfillset(&sa.sa_mask);
    assert (sigaction(sig, &sa, nullptr) != -1);
}

int main(int argc, char* argv[]) {
    if (argc <= 2)
    {
        cerr << "Usage " << agrv[0] << " <ip> <port>" << endl;
        return -1; 
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = port;

    int listenFd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listen >= 0);

    int ret = bind(listenFd, (struct sockaddr*)&address, sizeof(address));
    assert(ret != -1);

    ret = listen(listen, 5);
    assert(ret != -1);

    struct sockaddr_in clientAddr;
    socklen_t clientAddrLen = sizeof(clientAddr);
    int connFd = accept(listenFd,(struct sockaddr*)&clientAddr, &clientAddrLen);
    if (connFd <0) {
        cout << "errno is: " << errno << endl;
    }
    else {
        addsig(SIGURG, sig_urg);
        fcnt(connFd, F_SEROWN, gitpid());

        char buffer[BUF_SIZE];
        while(1) {
            memset(&buffer, 0, BUF_SIZE);
            ret = recv(connFd, buffer, BUF_SIZE - 1, 0);
            if (ret <= 0) {
                break;
            }
            cout << "got " << ret << " bytes of normal data" << buffer << endl;
        }
        close(connFd);
    }

    close(listenFd);
    return 0;
}